package JavaEE.ManyThread3;
import java.util.*;
public class Demo1 {
    // 锁:将"非原子"的操作加锁,变成"原子"操作
    public static Object locker = new Object();
    public static int n = 0;
    /*
     * 出现线程问题的原因:
     * 1. 线程的调度执行是随机的[根本原因]
     * 2. 多个线程同时修改同一个变量
     * 3. 修改操作不是"原子"的
     */
    public static void main(String[] args) throws InterruptedException{
        // 如果不是50000,而是5000,500,则可以"巧合的"保证结果正确
        // 这是因为for循环次数少,线程可能在极短时间内完成,操作系统可能不会切换线程,因此不会竞争!
        Thread t1 = new Thread(() -> {
            // 提问:如果将n定义在main内部,是否能成功运行?
            for(int i = 0;i < 50000;i++){
                // 加锁可以解决
                // synchronized (locker) {
                n++;
                // }
            }
        });
        Thread t2 = new Thread(() -> {
            for(int i = 0;i < 50000;i++){
                // synchronized (locker) {
                n++;
                // }
            }
        });
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        // 期望:100000
        // 实际: < 100000
        System.out.println(n);

        // (线程安全问题!!! *重要*)
        // 在cpu内部,n++其实是"三个指令":
        // "load":把内存中的数值,加载到cpu寄存器里
        // "add":把寄存器中的数据进行+1,结果放回寄存器
        // "save":把寄存器中的值写回内存.

        // 指令是"机器语言"cpu执行的任务具体细节
        // cpu会一条一条的"读取指令,解析指令,执行指令"
        // "操作系统调度线程是 随机的"
        // 每个线程执行到任意一个指令时都可能触发cpu的调度
        // 可能:
        // load1 -> 将0存入寄存器 -> 寄1 = 0;
        // load2 -> 将0存入寄存器 -> 寄2 = 0;
        // add1 -> 寄1 = 0++ = 1;
        // save1 -> 寄1 -> 内存: 0->1
        // add2 -> 寄2 = 0++ = 1；
        // save2 -> 寄2 -> 内存: 1->1 /* 但理想状态为2 */

    }
}
